//+------------------------------------------------------------------+
//|                    ChartCanvas.mqh 图表绘图画布基类头文件         |
//|                版权所有 2000-2025, MetaQuotes Ltd.              |
//|                        官方网址: https://www.mql5.com            |
//+------------------------------------------------------------------+
#include "../Canvas.h"            // 引入 2D 绘图画布基类 CCanvas
#include <Arrays/ArrayInt.h>      // 引入整数数组类（用于索引管理）
#include <Arrays/ArrayUInt.h>     // 引入无符号整数数组类（用于颜色管理）
#include <Arrays/ArrayDouble.h>   // 引入双精度数组类（用于数据存储）
#include <Arrays/ArrayString.h>   // 引入字符串数组类（用于描述符管理）

//+------------------------------------------------------------------+
//| 图表显示控制标志枚举（控制图表各组件的可见性）                   |
//+------------------------------------------------------------------+
enum ENUM_SHOW_FLAGS
  {
   FLAG_SHOW_NONE        = 0,         // 隐藏所有组件
   FLAG_SHOW_LEGEND      = 1,         // 显示图例（数据系列的颜色与名称说明）
   FLAG_SHOW_SCALE_LEFT  = 2,         // 显示左侧数值轴（垂直轴）
   FLAG_SHOW_SCALE_RIGHT = 4,         // 显示右侧数值轴（垂直轴）
   FLAG_SHOW_SCALE_TOP   = 8,         // 显示顶部轴（水平轴）
   FLAG_SHOW_SCALE_BOTTOM= 16,        // 显示底部轴（水平轴）
   FLAG_SHOW_GRID        = 32,        // 显示网格线（辅助读数）
   FLAG_SHOW_DESCRIPTORS = 64,        // 显示数据描述符（数据点的标签）
   FLAG_SHOW_VALUE       = 128,       // 显示实际数值（数据点的原始值）
   FLAG_SHOW_PERCENT     = 256,       // 显示百分比（数据点占总量的比例）
   FLAGS_SHOW_SCALES     = (FLAG_SHOW_SCALE_LEFT + FLAG_SHOW_SCALE_RIGHT + 
                           FLAG_SHOW_SCALE_TOP + FLAG_SHOW_SCALE_BOTTOM), // 显示所有轴
   FLAGS_SHOW_ALL        = (FLAG_SHOW_LEGEND + FLAGS_SHOW_SCALES + FLAG_SHOW_GRID + 
                           FLAG_SHOW_DESCRIPTORS + FLAG_SHOW_VALUE + FLAG_SHOW_PERCENT) // 显示所有组件
  };

//+------------------------------------------------------------------+
//| 图例对齐方式枚举（控制图例在图表中的位置）                       |
//+------------------------------------------------------------------+
enum ENUM_ALIGNMENT
  {
   ALIGNMENT_LEFT        = 1,   // 左对齐（图例显示在图表左侧）
   ALIGNMENT_TOP         = 2,   // 上对齐（图例显示在图表顶部）
   ALIGNMENT_RIGHT       = 4,   // 右对齐（图例显示在图表右侧）
   ALIGNMENT_BOTTOM      = 8    // 下对齐（图例显示在图表底部）
  };

//+------------------------------------------------------------------+
//| 显示状态判断宏（简化代码中对显示标志的判断）                     |
//+------------------------------------------------------------------+
#define IS_SHOW_LEGEND          ((m_show_flags & FLAG_SHOW_LEGEND)      != 0)  // 是否显示图例
#define IS_SHOW_SCALES          ((m_show_flags & FLAGS_SHOW_SCALES)     != 0)  // 是否显示所有轴
#define IS_SHOW_SCALE_LEFT      ((m_show_flags & FLAG_SHOW_SCALE_LEFT)  != 0)  // 是否显示左侧轴
#define IS_SHOW_SCALE_RIGHT     ((m_show_flags & FLAG_SHOW_SCALE_RIGHT) != 0)  // 是否显示右侧轴
#define IS_SHOW_SCALE_TOP       ((m_show_flags & FLAG_SHOW_SCALE_TOP)   != 0)  // 是否显示顶部轴
#define IS_SHOW_SCALE_BOTTOM    ((m_show_flags & FLAG_SHOW_SCALE_BOTTOM)!= 0)  // 是否显示底部轴
#define IS_SHOW_GRID            ((m_show_flags & FLAG_SHOW_GRID)        != 0)  // 是否显示网格
#define IS_SHOW_DESCRIPTORS     ((m_show_flags & FLAG_SHOW_DESCRIPTORS) != 0)  // 是否显示描述符
#define IS_SHOW_VALUE           ((m_show_flags & FLAG_SHOW_VALUE)       != 0)  // 是否显示实际数值
#define IS_SHOW_PERCENT         ((m_show_flags & FLAG_SHOW_PERCENT)     != 0)  // 是否显示百分比

//+------------------------------------------------------------------+
//| CChartCanvas 类                                                  |
//| 功能：MT5 图表绘制基础类，基于 2D 画布实现通用图表组件（轴、网格、图例等）|
//| 继承关系：public CCanvas（基于 2D 绘图画布类，扩展图表专用能力）  |
//| 核心特性：                                                      |
//|  1. 支持图表外观配置（背景色、边框色、文本色、网格色）            |
//|  2. 灵活控制图表组件可见性（轴、网格、图例、数据标签等）          |
//|  3. 支持数值轴参数配置（范围、刻度数量、精度）                    |
//|  4. 提供数据管理接口（描述符、颜色、偏移量更新）                  |
//|  5. 可继承扩展实现具体图表类型（柱状图、折线图、饼图等）          |
//+------------------------------------------------------------------+
class CChartCanvas : public CCanvas
  {
protected:
   //--- 图表外观颜色参数
   uint              m_color_background;  // 背景色（默认白色 XRGB(0xFF,0xFF,0xFF)）
   uint              m_color_border;      // 边框色（默认灰色 XRGB(0x9F,0x9F,0x9F)）
   uint              m_color_text;        // 文本色（默认深灰色 XRGB(0x3F,0x3F,0x3F)）
   uint              m_color_grid;        // 网格色（默认浅灰色 XRGB(0xCF,0xCF,0xCF)）

   //--- 图表适配与显示控制参数
   uint              m_max_data;          // 最大数据系列数量（默认10，超出部分自动处理）
   uint              m_max_descr_len;     // 描述符最大长度（默认10，超出部分会截断）
   uint              m_allowed_show_flags;// 允许显示的组件标志（默认 FLAGS_SHOW_ALL，即所有组件可显示）
   uint              m_show_flags;        // 当前显示的组件标志（默认 FLAG_SHOW_NONE，即隐藏所有组件）
   ENUM_ALIGNMENT    m_legend_alignment;  // 图例对齐方式（默认 ALIGNMENT_BOTTOM，底部对齐）
   uint              m_threshold_drawing; // 绘图阈值（默认2，低于该百分比的数据归为“其他”）
   bool              m_accumulative;      // 累积模式标志（true 表示数据累积显示，如堆叠图）

   //--- 数值轴与网格参数
   double            m_v_scale_min;       // 垂直轴最小值（默认0.0）
   double            m_v_scale_max;       // 垂直轴最大值（默认10.0）
   uint              m_num_grid;          // 网格线数量（默认5，即垂直轴分为5等份）
   int               m_scale_digits;      // 轴标签精度（小数位数，默认0）

   //--- 数据管理参数
   int               m_data_offset;       // 数据偏移量（控制数据显示的起始位置，默认0）
   uint              m_data_total;        // 有效数据系列数量（实际加载的数据条数）
   CArray           *m_data;              // 数据存储指针（指向具体数据数组，如 CArrayDouble）
   CArrayUInt        m_colors;            // 数据系列颜色数组（每个数据系列对应一个颜色）
   CArrayString      m_descriptors;       // 数据系列描述符数组（每个数据系列的名称/标签）

   //--- 内部计算与渲染参数
   CArrayInt         m_index;             // 有效数据索引数组（过滤无效数据后的索引）
   uint              m_index_size;        // 有效数据索引数量（m_index 的实际长度）
   double            m_sum;               // 数据总和（用于计算百分比，仅单系列数据有效）
   double            m_others;            // “其他”类别数据总和（低于阈值的数据累加）
   uint              m_max_descr_width;   // 描述符最大宽度（像素，用于图例布局）
   uint              m_max_value_width;   // 数值最大宽度（像素，用于数据标签布局）
   CRect             m_data_area;         // 数据绘制区域（排除轴、图例后的实际绘图区域）
   double            m_scale_x;           // 水平轴缩放比例（像素/单位数据，内部计算）
   int               m_x_min;             // 水平轴最小像素坐标（内部计算）
   int               m_x_0;               // 水平轴原点像素坐标（内部计算）
   int               m_x_max;             // 水平轴最大像素坐标（内部计算）
   int               m_dx_grid;           // 水平网格线间距（像素，内部计算）
   double            m_scale_y;           // 垂直轴缩放比例（像素/单位数据，内部计算）
   int               m_y_min;             // 垂直轴最小像素坐标（内部计算）
   int               m_y_0;               // 垂直轴原点像素坐标（内部计算）
   int               m_y_max;             // 垂直轴最大像素坐标（内部计算）
   int               m_dy_grid;           // 垂直网格线间距（像素，内部计算）
   string            m_scale_text[];      // 轴标签文本数组（存储垂直轴各刻度的显示文本）

public:
   /**
    * @brief 构造函数：初始化图表绘图画布实例
    * @details 调用父类 CCanvas 构造函数，初始化颜色、显示控制、轴参数等默认值
    */
                     CChartCanvas(void);

   /**
    * @brief 析构函数：销毁图表绘图画布实例
    * @details 释放数据存储指针（m_data），销毁 2D 画布资源
    */
                    ~CChartCanvas(void);

   //--- 画布创建接口（重写父类方法，添加图表默认配置）
   /**
    * @brief 创建图表画布资源（初始化尺寸、颜色格式，设置默认字体）
    * @param name [in] 画布资源名称（用于标识图表对象）
    * @param width [in] 画布宽度（像素，必须 >0）
    * @param height [in] 画布高度（像素，必须 >0）
    * @param clrfmt [in] 颜色处理格式（默认 COLOR_FORMAT_XRGB_NOALPHA，无透明度）
    * @return bool - 操作结果：true 表示画布创建成功，false 表示失败
    * @note 内部会设置默认字体为 "Tahoma"，大小为 10（通过 FontSet 实现）
    */
   virtual bool      Create(const string name,const int width,const int height,ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_XRGB_NOALPHA);

   //--- 图表颜色配置接口（读写）
   /**
    * @brief 获取背景色
    * @return uint - 背景色（XRGB 格式，如 0xFFFFFF 表示白色）
    */
   uint              ColorBackground(void) const { return(m_color_background); }

   /**
    * @brief 设置背景色
    * @param value [in] 背景色（XRGB 格式）
    * @note 设置后若有数据，会自动触发图表重绘
    */
   void              ColorBackground(const uint value);

   /**
    * @brief 获取边框色
    * @return uint - 边框色（XRGB 格式）
    */
   uint              ColorBorder(void) const { return(m_color_border); }

   /**
    * @brief 设置边框色
    * @param value [in] 边框色（XRGB 格式）
    * @note 设置后若有数据，会自动触发图表重绘
    */
   void              ColorBorder(const uint value);

   /**
    * @brief 获取文本色（轴标签、图例等文本的颜色）
    * @return uint - 文本色（XRGB 格式）
    */
   uint              ColorText(void) const { return(m_color_text); }

   /**
    * @brief 设置文本色
    * @param value [in] 文本色（XRGB 格式）
    * @note 设置后若有数据，会自动触发图表重绘
    */
   void              ColorText(const uint value);

   /**
    * @brief 获取网格色
    * @return uint - 网格色（XRGB 格式）
    */
   uint              ColorGrid(void) const { return(m_color_grid); }

   /**
    * @brief 设置网格色
    * @param value [in] 网格色（XRGB 格式）
    * @note 设置后若有数据，会自动触发图表重绘
    */
   void              ColorGrid(const uint value) { m_color_grid=value; }

   //--- 图表适配参数配置接口（读写）
   /**
    * @brief 获取最大数据系列数量
    * @return uint - 最大数据系列数量（默认10）
    */
   uint              MaxData(void) const { return(m_max_data); }

   /**
    * @brief 设置最大数据系列数量
    * @param value [in] 最大数量（必须 >0，超出部分会被截断或归为“其他”）
    * @note 若当前数据量超过新设置的最大值，会自动截断数据并更新颜色/描述符数组
    */
   void              MaxData(const uint value);

   /**
    * @brief 获取描述符最大长度
    * @return uint - 描述符最大长度（默认10，单位：字符）
    */
   uint              MaxDescrLen(void) const { return(m_max_descr_len); }

   /**
    * @brief 设置描述符最大长度
    * @param value [in] 最大长度（单位：字符，超出部分会被截断）
    * @note 设置后若有数据，会自动触发图表重绘
    */
   void              MaxDescrLen(const uint value);

   //--- 图表组件显示控制接口
   /**
    * @brief 设置允许显示的组件标志（限制可控制的组件范围）
    * @param flags [in] 允许显示的标志（组合 ENUM_SHOW_FLAGS，如 FLAGS_SHOW_SCALES 仅允许控制轴）
    * @note 若当前显示的组件不在允许范围内，会自动隐藏该组件
    */
   void              AllowedShowFlags(const uint flags);

   /**
    * @brief 获取当前显示的组件标志
    * @return uint - 当前显示标志（组合 ENUM_SHOW_FLAGS）
    */
   uint              ShowFlags(void) const { return(m_show_flags); }

   /**
    * @brief 设置当前显示的组件标志
    * @param flags [in] 显示标志（组合 ENUM_SHOW_FLAGS，需在 AllowedShowFlags 范围内）
    * @note 设置后若有数据，会自动触发图表重绘
    */
   void              ShowFlags(const uint flags);

   /**
    * @brief 判断是否显示图例
    * @return bool - 显示状态：true 表示显示，false 表示隐藏
    */
   bool              IsShowLegend(void)          const { return(IS_SHOW_LEGEND);       }

   /**
    * @brief 判断是否显示左侧轴
    * @return bool - 显示状态：true 表示显示，false 表示隐藏
    */
   bool              IsShowScaleLeft(void)       const { return(IS_SHOW_SCALE_LEFT);   }

   /**
    * @brief 判断是否显示右侧轴
    * @return bool - 显示状态：true 表示显示，false 表示隐藏
    */
   bool              IsShowScaleRight(void)      const { return(IS_SHOW_SCALE_RIGHT);  }

   /**
    * @brief 判断是否显示顶部轴
    * @return bool - 显示状态：true 表示显示，false 表示隐藏
    */
   bool              IsShowScaleTop(void)        const { return(IS_SHOW_SCALE_TOP);    }

   /**
    * @brief 判断是否显示底部轴
    * @return bool - 显示状态：true 表示显示，false 表示隐藏
    */
   bool              IsShowScaleBottom(void)     const { return(IS_SHOW_SCALE_BOTTOM); }

   /**
    * @brief 判断是否显示网格
    * @return bool - 显示状态：true 表示显示，false 表示隐藏
    */
   bool              IsShowGrid(void)            const { return(IS_SHOW_GRID);         }

   /**
    * @brief 判断是否显示描述符
    * @return bool - 显示状态：true 表示显示，false 表示隐藏
    */
   bool              IsShowDescriptors(void)     const { return(IS_SHOW_DESCRIPTORS);  }

   /**
    * @brief 判断是否显示百分比
    * @return bool - 显示状态：true 表示显示，false 表示隐藏
    */
   bool              IsShowPercent(void)         const { return(IS_SHOW_PERCENT);      }

   /**
    * @brief 设置是否显示图例
    * @param flag [in] 显示状态：true 显示，false 隐藏（默认 true）
    * @note 需在 AllowedShowFlags 允许范围内，设置后自动触发重绘
    */
   void              ShowLegend(const bool flag=true);

   /**
    * @brief 设置是否显示左侧轴
    * @param flag [in] 显示状态：true 显示，false 隐藏（默认 true）
    * @note 需在 AllowedShowFlags 允许范围内，设置后自动触发重绘
    */
   void              ShowScaleLeft(const bool flag=true);

   /**
    * @brief 设置是否显示右侧轴
    * @param flag [in] 显示状态：true 显示，false 隐藏（默认 true）
    * @note 需在 AllowedShowFlags 允许范围内，设置后自动触发重绘
    */
   void              ShowScaleRight(const bool flag=true);

   /**
    * @brief 设置是否显示顶部轴
    * @param flag [in] 显示状态：true 显示，false 隐藏（默认 true）
    * @note 需在 AllowedShowFlags 允许范围内，设置后自动触发重绘
    */
   void              ShowScaleTop(const bool flag=true);

   /**
    * @brief 设置是否显示底部轴
    * @param flag [in] 显示状态：true 显示，false 隐藏（默认 true）
    * @note 需在 AllowedShowFlags 允许范围内，设置后自动触发重绘
    */
   void              ShowScaleBottom(const bool flag=true);

   /**
    * @brief 设置是否显示网格
    * @param flag [in] 显示状态：true 显示，false 隐藏（默认 true）
    * @note 需在 AllowedShowFlags 允许范围内，设置后自动触发重绘
    */
   void              ShowGrid(const bool flag=true);

   /**
    * @brief 设置是否显示描述符
    * @param flag [in] 显示状态：true 显示，false 隐藏（默认 true）
    * @note 需在 AllowedShowFlags 允许范围内，设置后自动触发重绘
    */
   void              ShowDescriptors(const bool flag=true);

   /**
    * @brief 设置是否显示实际数值（与百分比互斥）
    * @param flag [in] 显示状态：true 显示数值，false 隐藏（默认 true）
    * @note 若设置为 true，会自动隐藏百分比显示，需在 AllowedShowFlags 允许范围内
    */
   void              ShowValue(const bool flag=true);

   /**
    * @brief 设置是否显示百分比（与实际数值互斥）
    * @param flag [in] 显示状态：true 显示百分比，false 隐藏（默认 true）
    * @note 若设置为 true，会自动隐藏实际数值显示，需在 AllowedShowFlags 允许范围内
    */
   void              ShowPercent(const bool flag=true);

   /**
    * @brief 设置图例对齐方式
    * @param value [in] 对齐方式（ENUM_ALIGNMENT 枚举，如 ALIGNMENT_BOTTOM 底部对齐）
    * @note 设置后若有数据，会自动触发图表重绘
    */
   void              LegendAlignment(const ENUM_ALIGNMENT value);

   /**
    * @brief 设置是否启用累积模式
    * @param flag [in] 累积模式：true 启用（如堆叠图），false 禁用（默认 true）
    * @note 设置后若有数据，会自动触发图表重绘
    */
   void              Accumulative(const bool flag=true);

   //--- 垂直轴参数配置接口（读写）
   /**
    * @brief 获取垂直轴最小值
    * @return double - 垂直轴最小值（默认 0.0）
    */
   double            VScaleMin(void) const { return(m_v_scale_min); }

   /**
    * @brief 设置垂直轴最小值
    * @param value [in] 最小值（必须 < VScaleMax，否则设置无效）
    * @note 设置后若有数据，会自动触发图表重绘
    */
   void              VScaleMin(const double value);

   /**
    * @brief 获取垂直轴最大值
    * @return double - 垂直轴最大值（默认 10.0）
    */
   double            VScaleMax(void) const { return(m_v_scale_max); }

   /**
    * @brief 设置垂直轴最大值
    * @param value [in] 最大值（必须 > VScaleMin，否则设置无效）
    * @note 设置后若有数据，会自动触发图表重绘
    */
   void              VScaleMax(const double value);

   /**
    * @brief 获取网格线数量（垂直轴刻度数量）
    * @return uint - 网格线数量（默认 5，即垂直轴分为 5 等份）
    */
   uint              NumGrid(void) const { return(m_num_grid); }

   /**
    * @brief 设置网格线数量（垂直轴刻度数量）
    * @param value [in] 数量（必须 >0，否则设置无效）
    * @note 设置后若有数据，会自动触发图表重绘
    */
   void              NumGrid(const uint value);

   /**
    * @brief 批量设置垂直轴参数（最大值、最小值、网格线数量）
    * @param max [in] 垂直轴最大值（必须 > min）
    * @param min [in] 垂直轴最小值（必须 < max）
    * @param grid [in] 网格线数量（必须 >0）
    * @note 一次完成三个参数设置，避免多次触发重绘，效率更高
    */
   void              VScaleParams(const double max,const double min,const uint grid);

   //--- 数据显示状态配置接口（读写）
   /**
    * @brief 获取数据偏移量（控制数据显示的起始位置）
    * @return int - 数据偏移量（默认 0，即从第一条数据开始显示）
    */
   int               DataOffset(void) const { return(m_data_offset); }

   /**
    * @brief 设置数据偏移量
    * @param value [in] 偏移量（正数表示向后偏移，负数表示向前偏移）
    * @note 设置后会自动触发图表重绘
    */
   void              DataOffset(const int value);

   //--- 数据管理接口（更新描述符与颜色）
   /**
    * @brief 获取有效数据系列数量
    * @return uint - 有效数据系列数量（实际加载的数据条数）
    */
   uint              DataTotal(void) const { return(m_data_total); }

   /**
    * @brief 更新指定位置的数据描述符（名称/标签）
    * @param pos [in] 数据位置索引（0 开始，需 < DataTotal）
    * @param descr [in] 新的描述符文本（长度不超过 MaxDescrLen）
    * @return bool - 操作结果：true 表示更新成功，false 表示索引无效或更新失败
    * @note 更新后会自动触发图表重绘
    */
   bool              DescriptorUpdate(const uint pos,const string descr);

   /**
    * @brief 更新指定位置的数据系列颜色
    * @param pos [in] 数据位置索引（0 开始，需 < DataTotal）
    * @param clr [in] 新的颜色（XRGB 格式，非 0）
    * @return bool - 操作结果：true 表示更新成功，false 表示索引无效或更新失败
    * @note 更新后会自动触发图表重绘
    */
   bool              ColorUpdate(const uint pos,const uint clr);

protected:
   /**
    * @brief 数据有效性检查（过滤无效数据，计算总和与“其他”类别）
    * @note 内部逻辑：
    *       - 单系列数据：计算总和，将低于阈值（m_threshold_drawing）的数据归为“其他”
    *       - 多系列数据：直接生成有效数据索引，不做阈值过滤
    */
   virtual void      ValuesCheck(void);

   /**
    * @brief 图表完整重绘（按顺序绘制背景、图例、轴、网格、描述符、数据）
    * @note 重绘流程：
    *       1. 计算数据绘制区域（排除轴、图例）
    *       2. 检查数据有效性（ValuesCheck）
    *       3. 依次绘制背景、图例、轴、网格、描述符、数据
    *       4. 刷新画布显示（Update）
    */
   virtual void      Redraw(void);

   /**
    * @brief 绘制图表背景与边框
    * @note 先填充背景色（m_color_background），再绘制边框（m_color_border）
    */
   virtual void      DrawBackground(void);

   /**
    * @brief 绘制图例（根据对齐方式调用纵向/横向绘制方法）
    * @note 内部根据 m_legend_alignment 调用 DrawLegendVertical 或 DrawLegendHorizontal
    */
   virtual void      DrawLegend(void);

   /**
    * @brief 纵向绘制图例（图例在左侧或右侧时调用）
    * @param w [in] 图例项宽度（像素，包含颜色块与文本）
    * @param h [in] 图例项高度（像素，文本高度）
    * @return int - 图例总宽度（像素，用于调整数据绘制区域）
    */
   int               DrawLegendVertical(const int w,const int h);

   /**
    * @brief 横向绘制图例（图例在顶部或底部时调用）
    * @param w [in] 图例项宽度（像素，包含颜色块与文本）
    * @param h [in] 图例项高度（像素，文本高度）
    * @return int - 图例总高度（像素，用于调整数据绘制区域）
    */
   int               DrawLegendHorizontal(const int w,const int h);

   /**
    * @brief 计算轴的像素坐标与缩放比例（为绘制轴做准备）
    * @note 内部计算：
    *       - 垂直轴的像素范围（m_y_min/m_y_max）、网格间距（m_dy_grid）
    *       - 轴标签文本（m_scale_text）、缩放比例（m_scale_y）
    */
   virtual void      CalcScales(void);

   /**
    * @brief 绘制所有启用的轴（根据显示标志调用对应轴的绘制方法）
    * @note 内部根据 m_show_flags 调用 DrawScaleLeft/DrawScaleRight/DrawScaleTop/DrawScaleBottom
    */
   virtual void      DrawScales(void);

   /**
    * @brief 绘制左侧轴（垂直轴）
    * @param draw [in] 是否实际绘制：true 绘制轴与标签，false 仅计算轴宽度
    * @return int - 左侧轴总宽度（像素，用于调整数据绘制区域）
    */
   virtual int       DrawScaleLeft(const bool draw=true);

   /**
    * @brief 绘制右侧轴（垂直轴）
    * @param draw [in] 是否实际绘制：true 绘制轴与标签，false 仅计算轴宽度
    * @return int - 右侧轴总宽度（像素，用于调整数据绘制区域）
    */
   virtual int       DrawScaleRight(const bool draw=true);

   /**
    * @brief 绘制顶部轴（水平轴）
    * @param draw [in] 是否实际绘制：true 绘制轴，false 仅计算轴高度
    * @return int - 顶部轴总高度（像素，用于调整数据绘制区域）
    */
   virtual int       DrawScaleTop(const bool draw=true);

   /**
    * @brief 绘制底部轴（水平轴）
    * @param draw [in] 是否实际绘制：true 绘制轴，false 仅计算轴高度
    * @return int - 底部轴总高度（像素，用于调整数据绘制区域）
    */
   virtual int       DrawScaleBottom(const bool draw=true);

   /**
    * @brief 绘制网格线（仅垂直方向，水平方向需子类扩展）
    * @note 绘制垂直网格线（平行于水平轴），颜色为 m_color_grid，样式为虚线（STYLE_DASH）
    */
   virtual void      DrawGrid(void);

   /**
    * @brief 绘制数据描述符（数据点的标签，空实现，需子类重写）
    * @note 基类仅定义接口，具体图表类型（如柱状图）需重写实现
    */
   virtual void      DrawDescriptors(void)       {}

   /**
    * @brief 绘制图表数据（调用 DrawData 绘制每条数据，空实现核心逻辑，需子类扩展）
    * @note 基类循环调用 DrawData 绘制每条数据，具体绘制逻辑（如柱状/折线）需子类重写 DrawData
    */
   virtual void      DrawChart(void);

   /**
    * @brief 绘制单条数据（空实现，需子类重写）
    * @param idx [in] 数据索引（0 开始，默认 0）
    * @note 基类仅定义接口，具体数据绘制逻辑（如绘制单根柱子/折线点）需子类重写
    */
   virtual void      DrawData(const uint idx=0)  {}
  };
//+------------------------------------------------------------------+